/**
 * huize Service Inc
 * All Rights Reserved @2018
 */
package com.huize.zhike.framework.common.util;


import com.huize.ladon.apm.common.util.DateTimeUtils;
import org.apache.commons.lang3.StringUtils;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.Period;
import java.time.ZoneId;
import java.util.Calendar;
import java.util.Date;
import java.util.regex.Pattern;

/**
 * 描述: 时间 日期 工具类
 *
 * @author tianyuliang
 * @version $Id: DatetimeUtils.java, v0.1 2021/2/4
 */
@SuppressWarnings("deprecation")
public class DatetimesUtils extends DateTimeUtils {

    public static final ZoneId ZONE_ID_SHANGHAI = ZoneId.of("Asia/Shanghai");

    public static final Pattern PTN_YYYY_MM_DD_HH_MM_SS = Pattern.compile("^\\d{4}-\\d{2}-\\d{2}\\s\\d{2}:\\d{2}:\\d{2}\\.\\d$");

    /**
     * 1天
     */
    public static final int ONE_DAY = 1;

    /**
     * 1周=7天
     */
    public static final int ONE_WEEK_DAY = 7;

    /**
     * 标准month格式
     */
    public final static String PATTERN_MONTHS = "yyyy-MM";

    /**
     * 扩展month格式
     */
    public final static String PATTERN_EXT_MONTHS = "yyyyMM";

    /**
     * 扩展date格式
     */
    public final static String PATTERN_EXT_DATE = "yyyyMMdd";

    /**
     * 标准week格式
     */
    public final static String PATTERN_WEEK = "yyyy-ww";

    /**
     * 1秒-毫秒数
     */
    public static final Long ONE_SECOND = 1 * 1000L;

    /**
     * 5分钟-毫秒数
     */
    public static final Long FIVE_MINUTE = 5 * 60 * 1000L;

    /**
     * 每分钟-秒数
     */
    public static final Long ONE_MINUTE_SECOND = 1 * 60 * ONE_SECOND;

    /**
     * 每小时-秒数
     */
    public static final Long ONE_HOUR_SECOND = 1 * 60 * 60 * ONE_SECOND;

    /**
     * 每天-秒数
     */
    public static final Long ONE_DAY_SECOND = 1 * 60 * 60 * 24L;

    /**
     * 每天-毫秒数
     */
    public static final Long ONE_DAY_MILLISECOND = 1 * 60 * 60 * 24 * 1000L;

    /**
     * 拓展time格式
     */
    public final static String PATTERN_EXT_TIME = "yyyyMMdd-HHmmss";

    /**
     * 拓展time格式 yyyyMMdd-HHmmss
     */
    public static ThreadLocal<SimpleDateFormat> extTimeLocal = new ThreadLocal<SimpleDateFormat>() {
        @Override
        protected SimpleDateFormat initialValue() {
            return new SimpleDateFormat(PATTERN_EXT_TIME);
        }
    };

    /**
     * 标准week格式 yyyy-ww
     */
    public static ThreadLocal<SimpleDateFormat> weekLocal = new ThreadLocal<SimpleDateFormat>() {
        @Override
        protected SimpleDateFormat initialValue() {
            return new SimpleDateFormat(PATTERN_WEEK);
        }
    };

    /**
     * date格式 yyyyMMdd
     */
    public static ThreadLocal<SimpleDateFormat> monthExtDate = new ThreadLocal<SimpleDateFormat>() {
        @Override
        protected SimpleDateFormat initialValue() {
            return new SimpleDateFormat(PATTERN_EXT_DATE);
        }
    };

    /**
     * 判断字符串(yyyyMMdd)能否转化为Date，返回true标识能够转化
     */
    public static boolean canParseExtDate(String value) {
        if (BaseUtils.isEmpty(value)) {
            return false;
        }
        Date date = parseExtDate(value.trim());
        return date != null;
    }

    /**
     * 判断字符串(yyyy-MM)能否转化为Date，返回true标识能够转化
     */
    public static boolean canParseMonth(String value) {
        Date date = parseCustomDate(value, PATTERN_MONTHS);
        return date != null;
    }

    /**
     * 判断字符串(yyyyMM)能否转化为Date，返回true标识能够转化
     */
    public static boolean canParseExtMonth(String value) {
        Date date = parseCustomDate(value, PATTERN_EXT_MONTHS);
        return date != null;
    }

    /**
     * 字符串(yyyyMM)转化为Date
     */
    public static Date parseExtMonth(String value) {
        Date date = parseCustomDate(value, PATTERN_EXT_MONTHS);
        return date;
    }

    /**
     * 将日期格式化为月份
     */
    public static String formatMonth(Date date) {
        return formatCustomDate(date, PATTERN_MONTHS);
    }

    /**
     * 将日期格式化为yyyyMM月份
     */
    public static String formatExtMonth(Date date) {
        return formatCustomDate(date, PATTERN_EXT_MONTHS);
    }

    /**
     * 将Date时间格式化为"yyyyMMdd-HHmmss"拓展时间
     */
    public static String formatExtTime(Date time) {
        if (time == null) {
            return "";
        }
        return extTimeLocal.get().format(time);
    }

    /**
     * 将字符串"yyyyMMdd-HHmmss"转化为Date时间
     */
    public static Date parseExtTime(String extDateTime) {
        try {
            SimpleDateFormat timeFormat = extTimeLocal.get();
            Date date = timeFormat.parse(extDateTime);
            return date;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 校验字符串"yyyyMMdd-HHmmss"能否转化为Date时间
     */
    public static boolean canParseExtTime(String extDateTime) {
        try {
            SimpleDateFormat timeFormat = extTimeLocal.get();
            Date date = timeFormat.parse(extDateTime);
            return date != null;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 将字符串转化为Date，转化过程优先适配"yyyy-MM-dd HH:mm:ss"， 失败后再次适配"yyyy-MM-dd"
     */
    public static Date parseDateTime(String strTime) {
        Date date = parseTime(strTime);
        if (date == null) {
            date = parseDate(strTime);
        }
        return date;
    }

    /**
     * 将字符串(yyyyMMdd)转化为Date
     */
    public static Date parseExtDate(String strDate) {
        Date date = null;
        try {
            SimpleDateFormat timeFormat = monthExtDate.get();
            date = timeFormat.parse(strDate);
        } catch (Exception e) {
            return null;
        }
        return date;
    }


    /**
     * 将Date格式化为字符串(yyyyMMdd)
     */
    public static String formatExtDate(Date date) {
        if (date == null) {
            return "";
        }
        SimpleDateFormat dateFormat = monthExtDate.get();
        return dateFormat.format(date);
    }

    /**
     * 计算2个日期差异，单位秒数
     */
    public static Long diffSecond(Date startDate, Date endDate) {
        long t0 = startDate.getTime();
        long t1 = endDate.getTime();
        long diff = t1 - t0;
        Long day = Double.valueOf(diff * 1D / ONE_SECOND).longValue();
        return day;
    }

    /**
     * 计算2个日期差异，单位月份
     */
    public static int diffMonth(String fromDate, String toDate) {
        return diffMonth(parseDate(fromDate), parseDate(toDate));
    }

    /**
     * 计算2个日期差异，单位月份
     */
    public static int diffMonth(Date fromDate, Date toDate) {
        if (fromDate == null || toDate == null) {
            throw new IllegalArgumentException("fromDate或者toDate参数无效!");
        }
        LocalDate startDate = fromDate.toInstant().atZone(ZONE_ID_SHANGHAI).toLocalDate();
        LocalDate endDate = toDate.toInstant().atZone(ZONE_ID_SHANGHAI).toLocalDate();
        Period period = Period.between(startDate, endDate);
        int diffMonth = period.getMonths();
        return diffMonth;
    }

    /**
     * 计算2个日期差异单位小时数
     */
    public static int diffHour(Date startDate, Date endDate) {
        long t0 = startDate.getTime();
        long t1 = endDate.getTime();
        long diff = t1 - t0;
        int hour = Double.valueOf(diff * 1D / ONE_HOUR_SECOND).intValue();
        return hour;
    }

    /**
     * 计算2个日期差异单位天数
     */
    public static int diffDay(String strStart, String strEnd) {
        Date startDate = parseDate(strStart);
        Date endDate = parseDate(strEnd);
        long t0 = startDate.getTime();
        long t1 = endDate.getTime();
        long diff = t1 - t0;
        int day = Double.valueOf(diff * 1D / ONE_DAY_MILLISECOND).intValue();
        return day;
    }

    /**
     * 计算2个日期差异单位天数
     */
    public static int diffMinute(Date startDate, Date endDate) {
        long t0 = startDate.getTime();
        long t1 = endDate.getTime();
        long diff = t1 - t0;
        int minute = Double.valueOf(diff * 1D / ONE_MINUTE_SECOND).intValue();
        return minute;
    }

    /**
     * 获取当月 总天数
     */
    public static int getTotalDaysFromMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
    }

    /**
     * 获取当月 目前天数
     */
    public static int getCurrentDaysFromMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.DAY_OF_MONTH);
    }

    /**
     * 获取当年 总天数
     */
    public static int getTotalDaysFromYear(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.getActualMaximum(Calendar.DAY_OF_YEAR);
    }

    /**
     * 获取当年 目前天数
     */
    public static int getCurrentDaysFromYear(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.DAY_OF_YEAR);
    }

    /**
     * 获取currentDate时间增加value秒的值
     */
    public static Date getNextSecond(Date currentDate, Long value) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(currentDate);
        calendar.add(Calendar.SECOND, value.intValue());
        return calendar.getTime();
    }

    /**
     * 获取currentDate时间减去value月的值
     */
    public static Date getPreMonth(Date currentDate, Integer value) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(currentDate);
        calendar.add(Calendar.MONTH, -value);
        return calendar.getTime();
    }

    /**
     * 获取currentDate时间减去value年的值
     */
    public static Date getPreYear(Date currentDate, Integer value) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(currentDate);
        calendar.add(Calendar.YEAR, -value);
        return calendar.getTime();
    }

    /**
     * 获取指定时间往后第X天
     */
    public static Date getNextDay(Date currentDate, int x) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(currentDate);
        calendar.add(Calendar.DATE, x);
        return calendar.getTime();
    }

    /**
     * 获取指定时间往后第X月
     */
    public static Date getNextMonth(Date currentDate, int x) {
        if (x == 0) {
            return currentDate;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(currentDate);
        calendar.add(Calendar.MONTH, x);
        return calendar.getTime();
    }


    /**
     * 获取指定日期的第0时0分0秒
     */
    public static Date getDateZeroHour(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        return c.getTime();
    }

    /**
     * 获取当前时间对应分钟的第0秒
     */
    public static Date getDateZeroSecond(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.set(Calendar.MILLISECOND, 0);
        return c.getTime();
    }

    /**
     * 获取当前时间对应小时的第0分0秒
     */
    public static Date getDateZeroMinute(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        return c.getTime();
    }

    /**
     * 获取当前时间对应 180天
     */
    public static Date getDateHalfYearDay(Date date) {
        Date value = getPreDay(date, 180);
        Calendar c = Calendar.getInstance();
        c.setTime(value);
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        return c.getTime();
    }

    /**
     * 获取当前时间对应 60天
     */
    public static Date getDateSixtyDay(Date date) {
        Date value = getPreDay(date, 60);
        Calendar c = Calendar.getInstance();
        c.setTime(value);
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        return c.getTime();
    }

    /**
     * 获取当前时间对应 月份第一天
     */
    public static Date getDateMonthOne(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.set(Calendar.DAY_OF_MONTH, 1);
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        return c.getTime();
    }

    /**
     * 获取当前时间对应 年份第1月第1天
     */
    public static Date getDateYearOne(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.set(Calendar.MONTH, 0);
        c.set(Calendar.DAY_OF_MONTH, 1);
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        return c.getTime();
    }

    /**
     * 按时间颗粒度转化Date
     */
    public static Date parseAdapterDate(String value) {
        if (canParseTime(value)) {
            return parseTime(value);
        } else if (canParseDate(value)) {
            return parseDate(value);
        } else {
            throw new RuntimeException("时间颗粒度unitEnum参数异常,无法转化时间" + value);
        }
    }

    /**
     * 校验是否为每年1月1日
     */
    public static boolean checkNewYearFirstDay(Date date) {
        if (date == null) {
            return false;
        }
        String val = formatDate(date);
        String[] values = val.split("-");
        boolean ok1 = values.length == 3 && StringUtils.isNotBlank(values[1]) && StringUtils.isNotBlank(values[2]);
        boolean ok2 = ok1 && values[1].equals("01") && values[2].equals("01");
        return ok2;
    }

    public static void main(String[] args) {
        System.out.println(formatTime(getDateMonthOne(new Date())));
        System.out.println(formatDate(getDateMonthOne(new Date())));
        System.out.println(formatTime(getDateYearOne(new Date())));
        System.out.println(formatDate(getDateYearOne(new Date())));
        System.out.println(checkNewYearFirstDay(parseDate("2022-05-20")));
        System.out.println(checkNewYearFirstDay(parseDate("2022-01-01")));
        System.out.println(checkNewYearFirstDay(parseDate("2022-01-07")));
        System.out.println(checkNewYearFirstDay(parseDate("2022-08-01")));
    }

}
